﻿using System;
using System.Collections.Generic;
using System.Linq;


using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;


using Action = Styx.TreeSharp.Action;


namespace Caldango
{
    public class Routine : CombatRoutine
    {

        public string OneHandWeapon = "Tyrannical Gladiator's Render";
        public string Shield = "Tyrannical Gladiator's Shield Wall";
        public string TwoHandWeapon = "Grievous Gladiator's Greatsword";

        /// <summary>
        /// The name of this CombatRoutine
        /// </summary>
        /// <value>
        /// The name.
        /// </value>
        public override string Name { get { return "Caldango"; } }


        /// <summary>
        /// The <see cref="T:Styx.WoWClass"/> to be used with this routine
        /// </summary>
        /// <value>
        /// The class.
        /// </value>
        public override WoWClass Class { get { return WoWClass.Warrior; } }


        private Composite _combat, _buffs;


        public override Composite CombatBehavior { get { return _combat; } }
        public override Composite PreCombatBuffBehavior { get { return _buffs; } }
        public override Composite CombatBuffBehavior { get { return _buffs; } }


        public override void Initialize()
        {
            _combat = CreateCombat();
            _buffs = CreateBuffs();
        }


        Composite CreateBuffs()
        {
            return Cast("Commanding Shout", ret => !StyxWoW.Me.HasAura("Commanding Shout") && StyxWoW.Me.IsAutoAttacking);
        }


        Composite CreateCombat()
        {
            return 
                //new Decorator(ret  => StyxWoW.Me.IsAlive && StyxWoW.Me.IsValid && UnfriendlyUnits60.Count() >= 1 && !StyxWoW.Me.Stunned && !StyxWoW.Me.Fleeing && !StyxWoW.Me.Pacified && !StyxWoW.Me.IsCasting && !StyxWoW.Me.IsChanneling   ,
                new PrioritySelector(
                     new Decorator(ret =>
                    !StyxWoW.Me.IsValid ||
                    !StyxWoW.IsInWorld ||
                    !StyxWoW.Me.IsAlive ||
                    StyxWoW.Me.Mounted ||
                    !StyxWoW.Me.GotTarget || 
                    !StyxWoW.Me.CurrentTarget.IsAlive ,
                        new Action(
                            delegate
                            {
                                return RunStatus.Success;
                            }
            )
            ),
 new Decorator(ret => StyxWoW.Me.CurrentTarget.HealthPercent <= 20,
                    CreateExecuteRange()),
                // Interrupt please.
                Cast("Mass Spell Reflection", ret => UnfriendlyUnitsCasting20.Count() >= 1),
                SpellReflection(),
                HandleTree(),
                Cast("Pummel", ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast && StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                Cast("Shockwave", ret=> SpellManager.Spells["Pummel"].Cooldown && StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast && StyxWoW.Me.CurrentTarget.Distance <= 8 && StyxWoW.Me.IsFacing(StyxWoW.Me.CurrentTarget)),
                Cast("Victory Rush", ret => StyxWoW.Me.HealthPercent <= 90 && StyxWoW.Me.HasAura("Victorious")),
                ShatteringThrow(),
                Equip2H(),
                new Decorator(ret => UnfriendlyUnitsTargetingMe.Count() >= 2 && (StyxWoW.Me.HealthPercent <= 40)  || StyxWoW.Me.HealthPercent <= 40, GoDefensive()),

                // Kee SS up if we've got more than 2 mobs to get to killing.
                new Decorator(ret => UnfriendlyUnits.Count() >= 2,
                    CreateAoe()),

                    
               

                new Decorator(ret => StyxWoW.Me.CurrentTarget.HealthPercent > 20,
                     CreateAttacks()
                    )
                )
                ;
        }

        public Composite HandleTree()
        {
            return
                new Decorator(ret =>
                    StyxWoW.Me.CurrentTarget.Class == WoWClass.Druid &&
                    StyxWoW.Me.CurrentTarget.HasAura(117679) &&
                    StyxWoW.Me.CurrentTarget.IsWithinMeleeRange,
                    new PrioritySelector(
                        Cast("Shockwave"  ),
                        Cast("Intimidating Shout", ret => SpellManager.Spells["Shockwave"].Cooldown && !StyxWoW.Me.CurrentTarget.Stunned)));
        }

        public Composite CreateAttacks()
        {
            return new PrioritySelector(

                        Cast("Hamstring", ret =>
                        StyxWoW.Me.CurrentTarget.IsPlayer && StyxWoW.Me.CurrentTarget.IsWithinMeleeRange &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Hamstring") &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Piercing Howl") &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Crippling Poison") &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Hand of Freedom") &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Sluggish") &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Infected Wounds") &&
                        StyxWoW.Me.CurrentTarget.Class != WoWClass.Paladin 
                      
                        ),

                                    // 

                                    //Cast("Battle Stance", ret => (StyxWoW.Me.HasAura("Defensive Stance") || StyxWoW.Me.HasAura("Berserker Stance")) && StyxWoW.Me.HealthPercent > 25),
                                    Cast("Mortal Strike", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                                    Cast("Colossus Smash", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                                    Cast("Slam", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                                    Cast("Overpower", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange && NeedTasteForBloodDump),
                                    // Rage dump!
                                    Cast("Heroic Strike", ret => (StyxWoW.Me.CurrentRage >=70 && StyxWoW.Me.CurrentTarget.IsWithinMeleeRange)),
                                    Cast("Battle Shout", ret => StyxWoW.Me.RagePercent < 30),
                                    // Don't use this in execute range, unless we need the heal. Thanks!
                                    Cast("Victory Rush", ret => StyxWoW.Me.CurrentTarget.HealthPercent > 20 || StyxWoW.Me.HealthPercent < 50));
        }
        public Composite Equip1H()
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                return

                    new Sequence(
                        new Action(delegate
                        {
                            Lua.DoString("RunMacroText(\"/equipslot 16 " + OneHandWeapon + "\")");
                            Lua.DoString("RunMacroText(\"/equipslot 17 " + Shield + "\")");
                            return RunStatus.Failure;
                        }
                        )
                    );
            }
        }
        public Composite SpellReflection()
        {
            return
                new Decorator(ret =>  UnfriendlyUnitsCastingOnMe.Count() >= 1 && SpellManager.Spells["Spell Reflection"].CooldownTimeLeft.TotalMilliseconds <= 10 && !StyxWoW.Me.HasAura(114028),
                    new Action(delegate
                        {
                            //Lua.DoString("RunMacroText(\"/equipslot 16 " + OneHandWeapon + "\")");
                            //Lua.DoString("RunMacroText(\"/equipslot 17 " + Shield + "\")");
                            SpellManager.Cast("Spell Reflection");
                        }
                            )
                            );

        }
        public Composite ShatteringThrow()
        {
            return
                new Decorator(ret => UnfriendlyUnitsShatter.Count() >= 1 && SpellManager.Spells["Shattering Throw"].CooldownTimeLeft.TotalMilliseconds <= 10,
                    new Action(delegate
                        {
                            
                                SpellManager.Cast("Shattering Throw");

                           
                        }
            )
            );
        }
        public Composite ShieldWall()
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                return
                    new Decorator(ret => !StyxWoW.Me.ActiveAuras.ContainsKey("Die by the Sword") && SpellManager.CanCast("Shield Wall"),
                    new Sequence(
                        new Action(delegate
                        {
                            //Equip1H();
                            SpellManager.Cast("Shield Wall");
                        }
                        )
                    ));
            }
        }

        #region UseHealthstone

        private static Composite UseHealthstone()
        {
            return new Decorator(
                ret =>
                StyxWoW.Me.Combat && StyxWoW.Me.HealthPercent < 20,
                new Action(delegate
                {
                    WoWItem hs = StyxWoW.Me.BagItems.FirstOrDefault(o => o.Entry == 5512); //5512 Healthstone
                    
                    {
                        hs.Use();
                        
                    }
                    return RunStatus.Failure;
                })
                );
        }

        #endregion


        public Composite Equip2H()
        {
            return
                new Decorator(
                ret =>
                StyxWoW.Me.Combat &&
                StyxWoW.Me.HealthPercent >= 25 &&
                !StyxWoW.Me.HasAura("Spell Reflection") &&
                !StyxWoW.Me.HasAura("Shield Wall") &&
                (SpellManager.CanCast("Battle Stance") || SpellManager.CanCast("Defensive Stance")) &&
                StyxWoW.Me.Inventory.Equipped.OffHand != null,
                    new Action(delegate
                    {
                        Lua.DoString("RunMacroText(\"/equipslot 16 " + TwoHandWeapon + "\")");
                        return RunStatus.Failure;

                    }
                    )
            );
        }

        Composite GoDefensive()
        {
            // Defensive Logic
            return new PrioritySelector(

                //Defensive if not already in Defensive Stance
                Cast("Defensive Stance", ret => (StyxWoW.Me.HasAura("Battle Stance") || StyxWoW.Me.HasAura("Berserker Stance"))),
                //Equip1H(),
                //Die by the sword if Shield Wall is not up and My HP is 25% or less and I'm in combat and at least one enemy is meleeing me
                Cast("Die by the Sword", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange &&
                    StyxWoW.Me.Combat &&
                    !StyxWoW.Me.ActiveAuras.ContainsKey("Shield Wall") &&
                    SpellManager.CanCast("Die by the Sword") &&
                    StyxWoW.Me.HealthPercent <= 25 &&
                    UnfriendlyUnitsTargetingMeinMeleeRange.Count() >= 1),

                //Fear if HP is 30% or less and 2 or more enemies in melee range
                Cast("Intimidating Shout", ret => UnfriendlyUnitsTargetingMeinMeleeRange.Count() >= 2 && StyxWoW.Me.HealthPercent <= 30 && SpellManager.CanCast("Intimidating Shout")),

                //Rallying cry if HP is 25% or less and I don't already have Sheild Wall or Die by the Sword up
                Cast("Rallying Cry", ret => StyxWoW.Me.HealthPercent <= 25 &&
                                            !StyxWoW.Me.ActiveAuras.ContainsKey("Die by the Sword") &&
                                            !StyxWoW.Me.ActiveAuras.ContainsKey("Shield Wall") &&
                                            SpellManager.CanCast("Rallying Cry")),

                //Disarm DK, Hunter, Rogue, Warrior
                Cast("Disarm", ret => (StyxWoW.Me.CurrentTarget.Class == WoWClass.DeathKnight ||
                                        StyxWoW.Me.CurrentTarget.Class == WoWClass.Hunter ||
                                        StyxWoW.Me.CurrentTarget.Class == WoWClass.Rogue ||
                                        StyxWoW.Me.CurrentTarget.Class == WoWClass.Warrior) &&
                                        StyxWoW.Me.CurrentTarget.IsWithinMeleeRange &&
                                        SpellManager.CanCast("Disarm")),
                //Cast Shield Wall
                ShieldWall(),
               
                //UseHealthstone
                UseHealthstone(),






               CreateAttacks()

                );
        }


        Composite CreateAoe()
        {
            return new PrioritySelector(
                Cast("Piercing Howl", ret =>
                        StyxWoW.Me.CurrentTarget.IsPlayer && StyxWoW.Me.CurrentTarget.Distance <= 10 &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Hamstring") &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Piercing Howl") &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Crippling Poison") &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Hand of Freedom") &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Sluggish") &&
                        !StyxWoW.Me.CurrentTarget.HasAura("Infected Wounds")
                        ),
                Cast("Mortal Strike", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                Cast("Colossus Smash", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                Cast("Slam", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                
                //Cast("Dragon Roar"),
                Cast("Shockwave", ret => StyxWoW.Me.CurrentTarget.Distance <= 8 && StyxWoW.Me.IsSafelyFacing(StyxWoW.Me.CurrentTarget)),
                //Shockwave is firing off premature or not when facing target?
                //Cast("Bladestorm", ret => UnfriendlyUnits.Count() >= 3),
                Cast("Sweeping Strikes", ret => UnfriendlyUnits.Count() >=2 && StyxWoW.Me.RagePercent > 60),
                Cast("Thunder Clap", ret => !StyxWoW.Me.CurrentTarget.HasAura("Weakened Blows")),
                Cast("Overpower", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange && NeedTasteForBloodDump),
                Cast("Whirlwind", ret => UnfriendlyUnits.Count() >= 3 && StyxWoW.Me.HasAura("Sweeping Strikes"))

                );
        }
        Composite CreateExecuteRange()
        {
            return new PrioritySelector(


                // Pop all our CDs. Get ready to truck the mob.



                Cast("Overpower", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange && StyxWoW.Me.HasAura("Sudden Execute")),
                Cast("Recklessness", ret=> StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                Cast("Berserker Rage", ret => StyxWoW.Me.CurrentRage <= 40 && StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                Cast("Battle Shout", ret => StyxWoW.Me.CurrentRage <= 40 && StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                Cast("Execute", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                Cast("Colossus Smash", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                Cast("Mortal Strike", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                Cast("Slam", ret => StyxWoW.Me.CurrentTarget.IsWithinMeleeRange),
                
                Cast("Heroic Throw", ret=> !StyxWoW.Me.CurrentTarget.IsWithinMeleeRange && StyxWoW.Me.CurrentTarget.Distance <= 30)
                




                );
        }


        Composite HeroicLeap()
        {
            return new Decorator(ret => StyxWoW.Me.CurrentTarget.HasAura("Colossus Smash") && SpellManager.CanCast("Heroic Leap"),
                new Action(ret =>
                {
                    var tpos = StyxWoW.Me.CurrentTarget.Location;
                    var trot = StyxWoW.Me.CurrentTarget.Rotation;
                    var leapRight = WoWMathHelper.CalculatePointAtSide(tpos, trot, 5, true);
                    var leapLeft = WoWMathHelper.CalculatePointAtSide(tpos, trot, 5, true);


                    var myPos = StyxWoW.Me.Location;


                    var leftDist = leapLeft.Distance(myPos);
                    var rightDist = leapRight.Distance(myPos);


                    var leapPos = WoWMathHelper.CalculatePointBehind(tpos, trot, 8);


                    if (leftDist > rightDist && leftDist <= 40 && leftDist >= 8)
                        leapPos = leapLeft;
                    else if (rightDist > leftDist && rightDist <= 40 && rightDist >= 8)
                        leapPos = leapLeft;


                    SpellManager.Cast("Heroic Leap");
                    SpellManager.ClickRemoteLocation(leapPos);
                    StyxWoW.Me.CurrentTarget.Face();
                }));
        }

        /*
        void UseTrinkets()
        {
            var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;
            var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;


            if (firstTrinket != null && CanUseEquippedItem(firstTrinket))
                firstTrinket.Use();


            if (secondTrinket != null && CanUseEquippedItem(secondTrinket))
                secondTrinket.Use();


        }*/
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }


        IEnumerable<WoWUnit> UnfriendlyUnits
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => !u.IsDead && u.CanSelect && u.Attackable && !u.IsFriendly && u.IsWithinMeleeRange); }
        }

        IEnumerable<WoWUnit> UnfriendlyUnits60
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => !u.IsDead && u.CanSelect && u.Attackable && !u.IsFriendly && u.Distance <= 60); }
        }

        IEnumerable<WoWUnit> UnfriendlyUnitsShatter
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => 
                !u.IsDead && 
                u.CanSelect && 
                (u.HasAura("Divine Shield") || u.HasAura("Ice Block")) &&
                !u.IsFriendly && 
                u.Distance <=30 ); }
        }

        IEnumerable<WoWUnit> UnfriendlyUnitsTargetingMe
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => !u.IsDead && u.CanSelect && u.Attackable && !u.IsFriendly && u.IsTargetingMeOrPet); }
        }
        IEnumerable<WoWUnit> UnfriendlyUnitsTargetingMeinMeleeRange
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u.IsWithinMeleeRange && !u.IsDead && u.CanSelect && u.Attackable && !u.IsFriendly && u.IsTargetingMeOrPet); }
        }

        IEnumerable<WoWUnit> UnfriendlyUnitsCasting20
        {
            get
            {
                return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(
                    u => !u.IsDead &&
                    u.CanSelect &&
                    u.Attackable &&
                    !u.IsFriendly &&
                    u.IsCasting &&
                    u.Distance <= 60 &&
                    (
                  u.CastingSpell.Name == "Cyclone" ||
                  (u.CastingSpell.Name == "Polymorph" && u.HealthPercent >= 65) ||
                  u.CastingSpell.Name == "Chaos Bolt" ||
                  u.CastingSpell.Name == "Frost Bomb" ||
                  u.CastingSpell.Name == "Frostjaw" ||
                  u.CastingSpell.Name == "Starfire" ||
                  u.CastingSpell.Name == "Starsurge" ||
                  u.CastingSpell.Name == "Mind Blast" ||
                  u.CastingSpell.Name == "Lava Burst" ||
                  u.CastingSpell.Name == "Chain Lightning" ||
                  u.CastingSpell.Name == "Hex" ||
                  u.CastingSpell.Name == "Fear" ||
                  u.CastingSpell.Name == "Unstable Affliction"
                    ) &&
                    (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember) && 
                    u.CurrentTarget.IsAlive &&
                    u.CurrentTarget.IsPlayer &&
                    u.CurrentTarget.Distance <= 20);
                //Members withing 20 yards
            }
        }
        IEnumerable<WoWUnit> UnfriendlyUnitsCastingOnMe
        {
            get
            {
                return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(
                    u => !u.IsDead &&
                    u.CanSelect &&
                    u.Attackable &&
                    u.Distance <= 40 &&
                    !u.IsFriendly &&
                    u.IsCasting &&
                    (
                  u.CastingSpell.Name == "Cyclone" ||
                  (u.CastingSpell.Name == "Polymorph" && u.HealthPercent >= 65) ||
                  u.CastingSpell.Name == "Chaos Bolt" ||
                  u.CastingSpell.Name == "Frost Bomb" ||
                  u.CastingSpell.Name == "Frostjaw" ||
                  u.CastingSpell.Name == "Starfire" ||
                  u.CastingSpell.Name == "Starsurge" ||
                  u.CastingSpell.Name == "Mind Blast" ||
                  u.CastingSpell.Name == "Lava Burst" ||
                  u.CastingSpell.Name == "Chain Lightning" ||
                  u.CastingSpell.Name == "Hex" ||
                  u.CastingSpell.Name == "Fear" ||
                  u.CastingSpell.Name == "Unstable Affliction"
                    ) &&
                    u.IsTargetingMeOrPet);
            }
        }


        bool NeedTasteForBloodDump
        {
            get
            {
                var tfb = StyxWoW.Me.GetAuraByName("Taste for Blood");
                if (tfb != null)
                {
                    // If we have more than 1 stacks, pop HS
                    if (tfb.StackCount >= 4)
                        return true;


                    // If it's about to drop, and we have at least 2 stacks, then pop HS.
                    // If we have 1 stack, then a slam is better used here.
                    if (tfb.TimeLeft.TotalSeconds <= 5 && tfb.StackCount > 1)
                        return true;
                }
                return false;
            }
        }


        bool NeedHeroicStrikeDump
        {
            get
            {
                // Flat out, drop HS if we need to.
                if (StyxWoW.Me.RagePercent >= 90)
                    return true;


                return NeedTasteForBloodDump;
            }
        }


        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret => SpellManager.Cast(spell)));
        }


        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }
    }
}